package club.ruanx.movie.controller;

import club.ruanx.acl.entity.SysParam;
import club.ruanx.acl.service.SysParamService;
import club.ruanx.bean.PageBean;
import club.ruanx.bean.ResultVO;
import club.ruanx.core.exception.TargetEntityNotFound;
import club.ruanx.movie.common.constraint.MovieParamConstraint;
import club.ruanx.movie.entity.Movie;
import club.ruanx.movie.param.MovieParam;
import club.ruanx.movie.service.MovieService;
import club.ruanx.movie.util.ParamUtils;
import club.ruanx.movie.vo.MovieVO;
import club.ruanx.util.BeanUtils;
import club.ruanx.util.CollectionUtils;
import club.ruanx.util.PagingUtils;
import club.ruanx.util.StringUtils;
import com.alibaba.fastjson.JSON;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.springframework.data.domain.Page;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import javax.validation.constraints.NotEmpty;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author 阮胜
 * @date 2018/10/21 20:18
 */
@RestController
@RequestMapping("/movie")
@Api(tags = "电影控制层")
public class MovieController {

    private final MovieService movieService;
    private final SysParamService sysParamService;

    public MovieController(MovieService movieService, SysParamService sysParamService) {
        this.movieService = movieService;
        this.sysParamService = sysParamService;
    }

    @ApiOperation("根据ID获取电影信息")
    @GetMapping("/{id}")
    public Movie findById(@PathVariable String id) throws TargetEntityNotFound {
        return movieService.findById(id);
    }

    @ApiOperation("根据ID获取电影详情")
    @GetMapping("/detail/{id}")
    public MovieVO findDetailById(@PathVariable String id) throws TargetEntityNotFound {
        movieService.increaseMovieHot(id, 1);
        Movie movie = movieService.findById(id);
        List<SysParam> movieTypeParamList = sysParamService.findAllByFlag(MovieParamConstraint.MOVIE_TYPE);
        List<SysParam> movieLanguageParamList = sysParamService.findAllByFlag(MovieParamConstraint.MOVIE_LANGUAGE);
        List<SysParam> movieAreaParamList = sysParamService.findAllByFlag(MovieParamConstraint.MOVIE_AREA);
        return parseToMovieVO(movieTypeParamList, movieLanguageParamList, movieAreaParamList, movie);
    }

    @ApiOperation("分页获取电影列表")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "page", value = "当前页", defaultValue = "0"),
            @ApiImplicitParam(name = "size", value = "每页的记录数", defaultValue = "10"),
    })
    @GetMapping("/list")
    public List<Movie> list(PageBean pageBean) {
        Page<Movie> moviePage = movieService.findAll(pageBean);
        PagingUtils.setNgxAdminPagingHeader(moviePage.getTotalElements());
        return moviePage.getContent();
    }

    @ApiOperation("分页获取电影列表(倒序)")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "page", value = "当前页", defaultValue = "0"),
            @ApiImplicitParam(name = "size", value = "每页的记录数", defaultValue = "10"),
    })
    @GetMapping("/list/desc")
    public List<Movie> listDesc(PageBean pageBean) {
        Page<Movie> moviePage = movieService.findAllOrderByCreateTimeDesc(pageBean);
        PagingUtils.setNgxAdminPagingHeader(moviePage.getTotalElements());
        return moviePage.getContent();
    }

    @ApiOperation("获取热门电影")
    @ApiImplicitParam(name = "count", value = "取前N条")
    @GetMapping("/hot/list/{count}")
    public List<MovieVO> hotVoList(@PathVariable Integer count) {
        List<Movie> movieList = movieService.findHotList(count);
        List<MovieVO> movieVOList = fillData(movieList);
        if (CollectionUtils.isEmpty(movieVOList)) {
            return new ArrayList<>();
        }
        movieVOList.forEach(movieVO -> movieVO.setHot(movieService.findMovieHot(movieVO.getId())));
        return movieVOList;
    }

    @ApiOperation("获取最新的电影")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "page", value = "当前页", defaultValue = "0"),
            @ApiImplicitParam(name = "size", value = "每页的记录数", defaultValue = "10"),
    })
    @GetMapping("/new/list")
    public List<MovieVO> newVoList(PageBean pageBean) {
        List<Movie> movieList = movieService.findByCreateTime(pageBean).getContent();
        return fillData(movieList);
    }

    @ApiOperation("根据类型获取电影")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "typeId", value = "类型"),
            @ApiImplicitParam(name = "page", value = "当前页", defaultValue = "0"),
            @ApiImplicitParam(name = "size", value = "每页的记录数", defaultValue = "10"),
    })
    @GetMapping("/type/{typeId}/list")
    public List<MovieVO> typeList(@PathVariable Integer typeId, PageBean pageBean) {
        Page<Movie> moviePage = movieService.findByType(typeId, pageBean);
        PagingUtils.setNgxAdminPagingHeader(moviePage.getTotalElements());
        List<Movie> movieList = moviePage.getContent();
        return fillData(movieList);
    }

    @ApiOperation("批量根据类型查询")
    @PostMapping("/type/list")
    public Map<String, List<MovieVO>> typeList(@RequestBody Integer[] types, PageBean pageBean) {
        Map<String, List<MovieVO>> movieMap = new LinkedHashMap<>(types.length);
        List<SysParam> movieTypeParamList = sysParamService.findAllByFlag(MovieParamConstraint.MOVIE_TYPE);
        for (Integer typeId : types) {
            String typeName = movieTypeParamList.stream()
                    .filter(sysParam -> sysParam.getValue()
                            .equals(String.valueOf(typeId)))
                    .map(SysParam::getName).findFirst().orElse(null);
            if (!StringUtils.isEmpty(typeName)) {
                List<Movie> movieList = movieService.findByType(typeId, pageBean).getContent();
                movieMap.put(typeName, fillData(movieList));
            }
        }
        return movieMap;
    }

    @ApiOperation("电影推荐,包含最新电影,热门电影,高分电影,站长推荐")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "typeId", value = "类型"),
            @ApiImplicitParam(name = "page", value = "当前页", defaultValue = "0"),
            @ApiImplicitParam(name = "size", value = "每页的记录数", defaultValue = "10"),
    })
    @GetMapping("/recommend/list")
    public Map<String, List<MovieVO>> recommendList(PageBean pageBean) {
        List<Movie> hotList = movieService.findHotList(pageBean.getSize());
        hotList.sort((o1, o2) -> o2.getRate() > o1.getRate() ? 1 : -1);
        List<Movie> rateList = movieService.findByRate(pageBean).getContent();
        List<Movie> newList = movieService.findByCreateTime(pageBean).getContent();
        Map<String, List<MovieVO>> movieMap = new LinkedHashMap<>(4);
        List<MovieVO> rateVOList = fillData(rateList);
        movieMap.put("热门电影", fillData(hotList));
        movieMap.put("最新电影", fillData(newList));
        movieMap.put("高分电影", rateVOList);
        return movieMap;
    }

    @ApiOperation("/根据评分获取电影列表")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "typeId", value = "类型"),
            @ApiImplicitParam(name = "page", value = "当前页", defaultValue = "0"),
            @ApiImplicitParam(name = "size", value = "每页的记录数", defaultValue = "10"),
    })
    @GetMapping("/rate/list")
    public List<MovieVO> rateList(PageBean pageBean) {
        List<Movie> movieList = movieService.findByRate(pageBean).getContent();
        return fillData(movieList);
    }

    @DeleteMapping("/delete/{id}")
    public ResultVO delete(@PathVariable String id) throws Exception {
        movieService.delete(id);
        return ResultVO.builder().success(true).message("从搜索引擎移除电影成功").build();
    }

    @PostMapping("/save")
    public Movie save(@RequestBody @Valid MovieParam movieParam) throws Exception {
        return movieService.save(movieParam);
    }


    @DeleteMapping("/delete")
    public List<String> deleteAll(String[] ids) {
        return movieService.deleteIn(ids);
    }

    /**
     * 将实体类转为VO对象
     *
     * @param movieList
     * @return
     */
    private List<MovieVO> fillData(List<Movie> movieList) {
        if (CollectionUtils.isEmpty(movieList)) {
            return null;
        }
        List<SysParam> movieTypeParamList = sysParamService.findAllByFlag(MovieParamConstraint.MOVIE_TYPE);
        List<SysParam> movieLanguageParamList = sysParamService.findAllByFlag(MovieParamConstraint.MOVIE_LANGUAGE);
        List<SysParam> movieAreaParamList = sysParamService.findAllByFlag(MovieParamConstraint.MOVIE_AREA);
        return movieList.stream()
                .map(movie -> parseToMovieVO(movieTypeParamList, movieLanguageParamList, movieAreaParamList, movie))
                .collect(Collectors.toList());
    }

    private MovieVO parseToMovieVO(List<SysParam> movieTypeParamList, List<SysParam> movieLanguageParamList,
                                   List<SysParam> movieAreaParamList, Movie movie) {
        List<String> typeList = JSON.parseArray(movie.getTypes(), String.class);
        List<String> languageList = JSON.parseArray(movie.getLanguages(), String.class);
        List<String> areaList = JSON.parseArray(movie.getAreas(), String.class);
        String[] types = ParamUtils.parseFieldValue(typeList, movieTypeParamList);
        String[] languages = ParamUtils.parseFieldValue(languageList, movieLanguageParamList);
        String[] areas = ParamUtils.parseFieldValue(areaList, movieAreaParamList);
        MovieVO movieVO = new MovieVO();
        BeanUtils.copyPropertiesIgnoreNull(movie, movieVO);
        movieVO.setTypes(types);
        movieVO.setLanguages(languages);
        movieVO.setAreas(areas);
        String photos = movie.getPhotos();
        if (!StringUtils.isEmpty(photos)) {
            String[] photoArr = JSON.parseArray(movie.getPhotos(), String.class).toArray(new String[1]);
            movieVO.setPhotos(photoArr);
        }
        return movieVO;
    }

    @GetMapping("/findByPersonName")
    public List<Movie> findByPersonName(@RequestParam(defaultValue = "") @NotEmpty String actor, @RequestParam(defaultValue = "") @NotEmpty String director, PageBean pageBean) {
        return movieService.findByActorOrDirector(actor, director, pageBean).getContent();
    }

}
